查看原文
其他

精通Linux系列九:查找文件位置(看完再也不担心找不到配置文件了)

拾叁 更AI 2023-10-21

点击关注公众号,AI&编程干货及时送达   

命令含义
find定位目录层次结构中的文件。
xargs处理定位到的文件列表(以及更多)。
locate创建文件索引,并搜索包含某字符串的索引。
which定位搜索路径(命令)中的可执行文件。
type定位搜索路径(bash内置)中的可执行文件。
whereis定位可执行文件,文档和源文件。

Linux系统可以轻松地包含数十万个文件。那么,当你需要查找特定文件时该如何操作呢?首先,你需要以一种有思考的方式将文件有逻辑地组织到目录中,但是还有几种其他方法可以找到文件,具体取决于你在寻找什么。

对于查找任何文件,find是一个暴力程序,它通过目录层次结构逐个文件地找到目标。locate的速度要快得多,它通过搜索你根据需要生成的预先构建的索引。(有些发行版默认每晚生成索引。)

对于查找程序,whichtype命令会检查你的shell搜索路径中的所有目录。type是内置在bash shell中的(因此只有在运行bash时才可用),而which是一个程序(通常是*/usr/bin/which*);type更快,可以检测shell别名[11]。相反,whereis会检查一组已知的目录,而不是你的搜索路径。

find

stdin  stdout  - file  -- opt  --help  --version

find [目录] [表达式]

find命令在一个或多个目录(以及它们的子目录)中搜索匹配某些条件的文件。它非常强大,有超过50个选项,不幸的是,其语法相当不寻常。下面是一些简单的示例,它们从当前目录(用点表示)搜索整个文件系统:

查找名为myfile的特定文件:

→ find . -type f -name myfile -print
./myfile

打印以“myfile”开头的文件名(注意通配符是如何转义的,这样shell就会忽略它):

→ find . -type f -name myfile\* -print
./myfile.zip
./myfile3
./myfile
./myfile2

打印所有目录名:

→ find . -type d -print
.
./jpegexample
./dir2
./mydir
./mydir/dir
./dir1
./dir3
./d

有用的选项

-name 模式-path 模式-lname 模式所需文件的名称 (-name),路径名 (-path),或符号链接目标 (-lname) 必须匹配这个shell模式,该模式可能包含shell通配符 *, ?, 和 []。(然而,你必须转义通配符,以便他们被shell忽略并直接传递给 find。)路径是相对于被搜索的目录树。
-iname 模式-ipath 模式-ilname 模式-iname-ipath, 和 -ilname选项分别与 -name-path, 和 -lname 相同,但不区分大小写。
-regex regexp路径(相对于正在搜索的目录树)必须匹配给定的正则表达式。
-type *t*仅定位类型为 t 的文件。这包括普通文件 (f),目录 (d),符号链接 (l),块设备 (b),字符设备 (c),命名管道 (p),和套接字 (s)。
-atime N-ctime N-mtime N文件最后访问时间 (-atime),最后修改时间 (-mtime),或状态改变时间 (-ctime) 正好是*N24 小时前。使用 +N * 表示 “大于 N ”,或 -N  表示 “小于 N ”。
-amin N-cmin N-mmin N文件最后访问时间 (-amin),最后修改时间 (-mmin),或状态改变时间 (-cmin) 正好是 N  分钟前。使用 +N  表示 “大于 N ”,或 -N  表示 “小于 N ”。
-anewer other_file-cnewer other_file-newer other_file文件的访问(-anewer),修改(-newer),或状态改变(-cnewer)的时间比*other_file*要新。
-maxdepth N-mindepth N只考虑在目录树深度至少(-mindepth)或最多(-maxdepthN  的文件。
-follow解引用符号链接。
-depth使用深度优先搜索:在操作目录本身之前,先完全搜索目录的内容(递归)。
-xdev限制搜索范围为单个文件系统(即,不跨设备边界)。
-size N [bckw]考虑文件大小为 N,可使用块(b)、单字节字符(c)、千字节(k)或双字节词(w)来表示。使用 +N  表示“大于 N”,或 -N  表示“小于 *N*”。
-empty文件大小为零,并且是常规文件或目录。
-user name文件由给定用户所有。
-group name文件由给定群组所有。
-perm mode文件具有等于模式的权限。使用 - mode 来检查给定的所有位是否被设置,或者使用 +mode 来检查给定的任何位是否被设置。

你可以使用以下运算符组合和否定表达式的部分:

  • • expression1-a *expression2与。(如果两个表达式并排出现,这是默认的,所以“-a”是可选的。)

  • • expression1-o *expression2或。

  • • ! *expression*

  • • -not *expression*否定表达式。

  • • ( *expression)优先级标记,就像在代数课上一样。先计算括号里的内容。你可能需要用“\”来避免shell解析这些内容。

  • • expression1, *expression2与C编程语言中的逗号运算符相同。评估两个表达式并返回第二个表达式的值。

一旦你确定了搜索标准,你就可以让find在符合标准的文件上执行这些操作。

有用的选项

-print直接打印文件的路径,相对于搜索目录。
-printf string打印给定的字符串,可能会应用C库函数printf()的方式进行替换。请参阅manpage以获取完整的输出列表。
-print0类似于-print,但输出的每一行不是用换行符,而是用零(ASCII 0)字符分隔。当你将find的输出通过管道传递给另一个程序,并且你的文件名列表可能包含空格字符时使用。当然,接收程序必须能够读取和解析这些零分隔的行(例如,xargs -0)。
-exec cmd ;调用给定的shell命令,*cmd*。确保转义任何shell元字符,包括所需的最后一个分号,以便它们不会立即在命令行上评估。此外,“{}”符号(确保引用或转义它)代表找到的文件的路径。完整的例子是:find . -exec ls '{}' \;
-ok cmd ;-exec相同,但在调用每个命令之前还会提示用户。
-ls在文件上执行命令 ls -dils

xargs

stdin  stdout  - 文件  -- 选项  --help  --version

xargs [选项] [命令]

xargs是shell中最奇特却又非常强大的命令之一。它从标准输入读取文本行,将它们转化为命令,并执行它们。这可能听起来并不激动人心,但xargs具有一些独特的用途,特别是用于处理你找到的文件列表。假设你创建了一个名为important的文件,其中每行列出一个重要文件:

→ cat important
/home/jsmith/mail/love-letters
/usr/local/lib/critical_stuff
/etc/passwd
...

利用xargs,你可以方便地使用其他Linux命令处理这些文件。例如,以下命令在所有列出的文件上运行ls -l命令:

→ cat important | xargs ls -l

同样,你可以用less查看文件:

→ cat important | xargs less

甚至可以用rm删除它们:

→ cat important | xargs rm -f    小心!这个操作是破坏性的!

每个管道都从important中读取文件列表,并根据列表生成并运行新的Linux命令。当输入列表不来自文件,而是来自另一个写入标准输出的命令时,就会展现出强大的功能。特别是find命令,它在标准输出上打印文件列表,与xargs配合使用效果非常好。例如,要在当前目录层次结构中搜索包含“tomato”一词的文件:

→ find . -type f -print | xargs grep -l tomato
./findfile1
./findfile2
→ cat findfile1
这个文件包含单词tomato。

这种能力伴随着一个警告:如果find找到的任何文件的名称包含空格,这将会使grep感到困惑。如果一个文件名叫(比如说)my stuff,那么构建的grep命令是:

grep -l tomato my stuff

这告诉grep要处理两个名为mystuff的文件。哎哟!现在想象一下如果程序是rm而不是grep。你会告诉rm删除错误的文件!为了避免这个问题,总是使用find -print0代替-print,它用ASCII零字符而不是换行符分隔行,然后用xargs -0,它期望ASCII零:

→ find . -type f -print0 | xargs -0 grep -l tomato

我们刚刚触及到了xargs命令的皮毛,所以继续实验吧!(首先用像grepls这样的无害命令!)

有用的选项

-n k将每个执行的命令的输入行数设置为*k*。常见的-n1保证每次执行只会处理一行输入。否则,xargs可能会将多行输入传递给一个命令。
-0将输入的行结束字符设置为ASCII零,而不是空格,并且按照字面意义处理所有字符。当输入来自find -print0时使用这个。

XARGS与反引号

如果你记得[“引用”],你可能会意识到,一些xargs技巧可以用反引号完成:

→ cat file_list | xargs rm -f   使用xargs
→ rm -f `cat file_list`          使用反引号
→ rm -f $(cat file_list)         使用$()

虽然这些命令做了类似的事情,但如果命令行在cat的输出展开后变得过长,以至于超过了shell命令行的最大长度,那么后两个命令可能会失败。xargs写入标准输出,而不是添加到命令行,所以它更安全,更适合大型或风险操作。

locate

stdin  stdout  - 文件  -- 选项  --help  --version

locate [选项]

locate命令及其伙伴updatedb,创建一个可以快速搜索的文件位置索引(数据库)[12]。如果你计划在一个不经常变动的目录层次结构中长时间搜索许多文件,那么locate是一个不错的选择。如果要找到单个文件或对找到的文件进行更复杂的处理,请使用find

一些发行版会定期(比如每天一次)自动索引整个文件系统,这样你就可以直接运行'locate(定位命令)'并让它工作。但是,如果你需要自己创建一个目录及其所有子目录的索引(例如,存储在'/tmp/myindex'),请运行:

→ updatedb -l0 -U directory -o /tmp/myindex

(注意,“-l0”是小写的'L'后面跟着一个零,不是数字10。)然后在索引中搜索字符串:

→ locate -d /tmp/myindex string

'locate(定位命令)'有一个有趣的可选安全特性。你可以创建一个索引,当搜索时,只会显示用户有权限查看的文件。所以,如果超级用户创建了一个受保护目录的索引,一个非超级用户可以搜索它,但不能看到受保护的文件。这是通过省略给'updatedb(更新数据库命令)'的'-l0'选项并以root身份运行它来完成的:

→ sudo updatedb -U directory -o /tmp/myindex

'updatedb(更新数据库命令)'的索引选项

-u从根目录向下创建索引。
-U directory从*directory*向下创建索引。
`-l (01)`
-e directories从索引中排除一个或多个目录。用逗号分隔它们的路径。
-o outfile将索引写入到文件*outfile*。

'locate(定位命令)'的搜索选项

-d index指示使用哪个索引(在我们的示例中,是'/tmp/myindex')。
-i不区分大小写的搜索。
-r regexp搜索匹配给定正则表达式的文件。

which

stdin  stdout  - file  -- opt  --help  --version

which file

'which(哪个)'命令在你的shell搜索路径中定位一个可执行文件。如果你通过键入其名称来调用一个程序:

→ who

'which(哪个)'命令会告诉你这个命令位于何处:

→ which who
/usr/bin/who

你甚至可以找到'which(哪个)'程序本身:

→ which which
/usr/bin/which

如果你的搜索路径中有几个程序有相同的名称(例如,'/usr/bin/who'和'/usr/local/bin/who'),'which(哪个)'只报告第一个。

type

stdin  stdout  - file  -- opt  --help  --version

type [options] commands

'type(类型)'命令,像'which(哪个)'一样,在你的shell搜索路径中定位一个可执行文件:

→ type grep who
grep is /bin/grep
who is /usr/bin/who

然而,'type(类型)'是内建在bash shell中的,而'which(哪个)'是磁盘上的一个程序:

→ type which type rm if
which is /usr/bin/which
type is a shell builtin
rm is aliased to `/bin/rm -i'
if is a shell keyword

作为一个内建在shell中的命令,'type(类型)'比'which(哪个)'更快;然而,它只在某些shell,如bash中可用。

whereis

stdin  stdout  - file  -- opt  --help  --version

whereis [options] files

'whereis(在哪)'命令试图通过搜索一个硬编码的目录列表来定位给定的文件。它可以找到可执行文件,文档和源代码。'whereis(在哪)'有点古怪,因为它的目录列表可能不包括你需要的目录。

→ whereis vim
vim: /usr/bin/vim /etc/vim /usr/share/vim ...

有用的选项

-b``-m``-s只列出可执行文件(-b),man页(-m)或源代码文件(-s)。
-B dirs... -f``-M dirs... -f``-S dirs... -f仅在给定的目录中搜索可执行文件(-B),man页(-M)或源代码文件(-S)。在列出你寻找的文件之前,必须用-f选项跟随目录列表。

推荐阅读

··································

你好,我是拾叁,7年开发老司机、互联网两年外企5年。怼得过阿三老美,也被PR comments搞崩溃过。这些年我打过工,创过业,接过私活,也混过upwork。赚过钱也亏过钱。一路过来,给我最深的感受就是不管学什么,一定要不断学习。只要你能坚持下来,就很容易实现弯道超车!所以,不要问我现在干什么是否来得及。如果你还没什么方向,可以先关注我,这里会经常分享一些前沿资讯和编程知识,帮你积累弯道超车的资本。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存